import os
WEENDIR="/me/steamapps/common/tw2"
def findAllFile(base):
    for root, ds, fs in os.walk(base):
        for f in fs:
            fullname = os.path.join(root, f)
            yield fullname

acc=''

for f in findAllFile(WEENDIR):
    with open(f) as x:
        F=x.read().split('\n')[:-1]
    tw='\n'.join(x for x in F if 'public static' in x and ('float duration,' in x or 'float duration)' in x) and not '>(' in x).replace('global::','').replace('\t','    ').replace('this ','')
    if len([x for x in tw.split('\n') if x!=''])==0 : continue
    nmsp=[x for x in F if 'namespace' in x][0].split('namespace')[1].split(' ')[1] if len('\n'.join(x for x in F if 'namespace' in x))>0 else 'junk'
    cls=[x for x in F if 'class' in x][0].split('class')[1].split(' ')[1] if len('\n'.join(x for x in F if 'class' in x))>0 else 'junk'
    if nmsp=='junk' and cls=='junk':
        continue
    elif nmsp=='junk' or cls=='junk':
        print(f"warning, invalid status in {f}")
        continue
    fcls=nmsp+'.'+cls
    curr=fcls.replace('.','_')
    register='foreach(var x in typeof('+curr+').GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public)){instructions = CopiedFragment.Register.SpeedUp(__originalMethod, instructions, typeof('+fcls+'), x);}'
    body='\n'.join(x+'{\n            duration*=CopiedFragment.Register.speed_factor;\n            return '+fcls+'.'+x.split('(')[0].split(' ')[-1]+'('+', '.join(x.split(' = ')[0].split(' ')[-1] for x in x.split('(')[1].split(')')[0].split(','))+');\n        }' for x in tw.split('\n') if x!='').replace('\t','    ')
    result='    // register : '+register+'\n    public static class '+curr+' {\n'+body+'\n    }\n'
    acc+=result

# print(acc)
with open("SpeedUp.CS",'w') as f:
    f.write("""// echo partial file, should not compile along
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using HarmonyLib;
using Utils;
using HarmonyLib.Tools;
namespace CopiedFragment;
public partial class CopiedFragment : TaiwuModdingLib.Core.Plugin.TaiwuRemakePlugin {
    public static class Register {
        public static float speed_factor=1f;
        public static IEnumerable<CodeInstruction> checker(IEnumerable<CodeInstruction> instructions, MethodInfo met, MethodInfo to){
            int line=0;
            foreach(var x in instructions){
                line++;
                if(x.operand == (object)met){
                    // logverbose($"中子Debug:found {met.Name} in {met.DeclaringType.Name} at line {line}");
                    var xx=x; // keep label if necessary
                    xx.opcode=OpCodes.Call;
                    xx.operand=to;
                    yield return xx;
                } else {
                    yield return x;
                }
            }
        }
        public static IEnumerable<CodeInstruction> SpeedUp(MethodBase __originalMethod, IEnumerable<CodeInstruction> instructions, Type type, MethodInfo to){
            MethodInfo met=type.GetMethod(to.Name, (BindingFlags)(-1), null, (from x in to.GetParameters() select x.ParameterType).ToArray(), null);
            if(met!=null){
                return checker(instructions,met,to);
            }
            // logwarn("Mod中子自用99新的动画Patch部分失效："+type.Name+"的"+to.Name+"方法不存在");
            return instructions;
        }
        public static IEnumerable<CodeInstruction> register(MethodBase __originalMethod, IEnumerable<CodeInstruction> instructions) {
            """
    +'\n            '.join(x.split('    // register : ')[1] for x in acc.split('\n') if '    // register : ' in x).replace('{','{\n                ').replace(';',';\n                ').replace('    }','}')
    +"""
            instructions = new CodeMatcher(instructions)
                .MatchForward(false, // false = move at the start of the match, true = move at the end of the match
                    new CodeMatch(i=>i.opcode==OpCodes.Call && (((MethodInfo)(i.operand)).Name=="SetDelay" || ((MethodInfo)(i.operand)).Name=="AppendInterval"))
                ).Repeat( matcher => // Do the following for each match
                    {
                        // logwarn("Found SetDelay in "+__originalMethod.Name);
                        matcher
                        .InsertAndAdvance(
                            new CodeInstruction(OpCodes.Ldc_R4,100f/F06),
                            new CodeInstruction(OpCodes.Mul)
                        ).Advance(1);
                    }
                ).InstructionEnumeration();
            return instructions;
        }
    }"""
    +'\n'
    +('\n'.join(x for x in acc.split('\n') if not '    // register : ' in x))
    +('}')
)

print("Warning: manually replace `DG.Tweening.DOTweenModuleUtils` to `DG.Tweening.DOTweenModuleUtils.Physics` is needed.")
